#include "serial.h"

/**************************************
Constructors
***************************************/

Serial::Serial()
{
    init(DEFAULTPORT, DEFAULTSPEED, DEFAULTDATABITS, DEFAULTBUFFERSIZE, DEFAULTPARITY, DEFAULTBUFFERINDEX, DEFAULTBLOCKING);
}

Serial::Serial(string device, double baudrate)
{
    init(device, baudrate, DEFAULTDATABITS, DEFAULTBUFFERSIZE, DEFAULTPARITY, DEFAULTBUFFERINDEX, DEFAULTBLOCKING);
}

Serial::Serial(string device, double baudrate, int databits, int buffersize, int par, int bufferindex, int blocking)
{
    init(device, baudrate, databits, buffersize, par, bufferindex, blocking);
}

void Serial::init(string device, double baudrate, int databits, int buffersize, int par, int bufferindex, int blocking)
{
    logger = new Log("Serial");
    logger->stuur("Setting up device with parameters");

    setDevice(device);
    setBaudRate(baudrate);
    setDataBits(databits);
    setBufferSize(buffersize);
    setBufferIndex(bufferindex);
    setParity(par);
    setBlockingMode(blocking);
}

/**************************************
Destructor
***************************************/

Serial::~Serial()
{
    logger->stuur("destructor called");
    // Kills the port
    closePort();
    delete logger;
}

/**************************************
Setters and getters
***************************************/

void Serial::setDevice(string device)
{
    logger->stuur("setting device");
    dev = device;
}

void Serial::setBaudRate(int baudrate)
{
    logger->stuur("setting baudrate");
    baud = baudrate;
}

void Serial::setDataBits(int bits)
{
    logger->stuur("setting databits");
    dataBits = bits;
}

void Serial::setBufferSize(int size)
{
    logger->stuur("Setting bufferSize");
    bufferSize = size;
}

void Serial::setBufferIndex(int index)
{
    logger->stuur("setting bufferindex");
    bufferIndex = index;
}

void Serial::setParity(int par)
{
    logger->stuur("Setting parity");
    parity = par;
}

void Serial::setBlockingMode(int blockingmode)
{
    logger->stuur("Setting blockingmode");
    blocking = blockingmode;
}

/***************************************
Functions
****************************************/

int Serial::initPort()
{

    // Try to open serial port with r/w access
    logger->stuur("opening device");
    fd = open(dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);

    // As long as port is actually open...
    if(fd != -1)
    {

        // Share the good news
        logger->stuur(5,"Init Serial port OK");

        // Configure port settings
        fcntl(fd, F_SETFL, FNDELAY);

        // Save current port settings so we don't corrupt anything on exit
        struct termios options;
        tcgetattr(fd, &options);

        // Convert integer baud to Baud type
        // Default to 9600 baud if none specified
        switch (baud)
        {
        case 4800:
            cfsetispeed(&options, B4800);
            cfsetospeed(&options, B4800);
            break;
        case 9600:
            cfsetispeed(&options, B9600);
            cfsetospeed(&options, B9600);
            break;
        case 19200:
            cfsetispeed(&options, B19200);
            cfsetospeed(&options, B19200);
            break;
        case 38400:
            cfsetispeed(&options, B38400);
            cfsetospeed(&options, B38400);
            break;
        case 57600:
            cfsetispeed(&options, B57600);
            cfsetospeed(&options, B57600);
            break;
        case 115200:
            cfsetispeed(&options, B115200);
            cfsetospeed(&options, B115200);
            break;
        default:
            cfsetispeed(&options, B9600);
            cfsetospeed(&options, B9600);
            break;
        }

        // Set options for proper port settings
        //	ie. 8 Data bits, No parity, 1 stop bit
        options.c_cflag |= (CLOCAL | CREAD);

        switch (parity)
        {
        case PARITY_7E1:
            // Parity, odd, 1 stop bit (7E1)
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            options.c_cflag &= ~CSTOPB;
            logger->stuur("Parity set to 7E1");
            break;
        case PARITY_8N1:
            // No parity, 1 stop bit (8N1)
            options.c_cflag |= CS8;
            logger->stuur("Parity set to 8N1");
            break;
        default:
            // No parity, 1 stop bit (8N1)
            options.c_cflag |= CS8;
            logger->stuur("No parity set");
            break;
        }

        // Set number of data bits.  Default is 8.
        switch (dataBits)
        {
        case 7:
            options.c_cflag |= CS7;
            logger->stuur("Databits set to 7");
            break;
        case 8:
            options.c_cflag |= CS8;
            logger->stuur("Databits set to 8");
            break;
        default:
            options.c_cflag |= CS8;
            logger->stuur("Databits not set!");
            break;
        }

        // Turn off hardware flow control
        options.c_cflag &= ~CRTSCTS;
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

        // Write our changes to the port configuration
        if(tcsetattr(fd, TCSANOW, &options) == 0)
        {
            logger->stuur("configuratie serial poort succesvol geschreven");
        }
        else
        {
            logger->stuur(1,"Fout bij het schrijven van de configuratie naar de seriele poort");
        }
    }

    // There was a problem, let's tell the user what it was
    else
    {
        logger->stuur(1,"Error opening serial port!");
        perror("Error opening port:");
        closePort();
        exit(1); //Moeten we een exit doen?
    }

    // Send back the public port file descriptor
    return fd;
}



int Serial::sendData(unsigned char* data, int len)
{

    // If the port is actually open, send the data
    if (fd != -1)
    {
        logger->stuur(5,"sendData is executed");
        printf("%d, %x, %x, %x",fd,data[0],data[1],data[2]);
        // Send the data and return the nubmer of bytes actually written
        //printf("Writing %s...\n", data);
        return write(fd, data, len);
    }
    // Port is closed!
    else return -1;
}



int Serial::sendChar(char data)
{
    switch (blocking)
    {
        // Non-blocking mode
    case 0:
        // If the port is actually open, send a byte
        if (fd != -1)
        {
            // Send the data and return number of bytes actually written

            write(fd, &data, 1);
            return 1;
        }
        else return -1;
        break;
        // Blocking mode
    case 1:
        // If the port is actually open, send a byte
        if (fd != -1)
        {
            // Send the data and return number of bytes actually written
            write(fd, &data, 1);
            return 1;
        }
        else return -1;
        break;
        // Blocking variable is messed up
    default:
        logger->stuur(1,"Error with blocking setting!");
        return -1;
        break;
    }
}

void Serial::closePort()
{

    // If the port is actually open, close it
    if (fd != -1)
    {
        close(fd);
        logger->stuur(5,"Serial device is now closed.");
    }
}
